import { createRequire } from 'node:module';

const require = createRequire(import.meta.url);
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');

export const IS_LINUX = os.platform() !== 'win32'; // linux系统
export const SPLIT_CHAR = IS_LINUX ? '/' : '\\'; // 系统分割线
export const ROOT_PATH = SPLIT_CHAR; // 根目录
export const TOS_PATH = path.resolve(ROOT_PATH, 'home', 'webos'); // tOS根目录
export const LOG_PATH = path.resolve(TOS_PATH, 'logs'); // 日志存储根目录，可修改
export const FILE_PATH = path.resolve(TOS_PATH, 'files'); // 存储根目录，可修改
export const PROJ_PATH = path.resolve(FILE_PATH, 'projects'); // 项目设计存储根目录，可修改
export const DEBUG_PATH = path.resolve(FILE_PATH, 'debug'); // 调试模式存储根目录，可修改
export const UPLOAD_PATH = path.resolve(FILE_PATH, 'uploads'); // 上传目录
export const APP_PATH = path.resolve(FILE_PATH, 'app'); // app目录
/**
 * creates a folder if it doesn't exist
 * @param path path to check
 */
export function createFolder(path) {
  const pathExists = fs.existsSync(path);
  if (pathExists) {
    console.log(`Directory ${path} already exists`);
  } else {
    fs.mkdirSync(path, { recursive: true });
    console.log(`Created directory ${path}`);
  }
}

/**
 * 是否系统或隐藏文件夹或
 * @param {*} folderPath
 * @returns boolean
 */
export function isSystemOrHiddenFolder(folderPath) {
  const folderStats = fs.statSync(folderPath);
  if (folderStats.isDirectory()) {
    const folderName = folderPath.split('/').pop(); // 获取文件夹名称
    if (
      !folderName.startsWith('.') &&
      !folderName.startsWith(`$`) &&
      !folderName.startsWith('/.') &&
      !folderName.startsWith(`/$`) &&
      !folderName.startsWith(String.raw`\.`) &&
      !folderName.startsWith(String.raw`\$`)
    ) {
      // 排除以.或$开头的文件夹
      return true;
    }
  }
  return false;
}
/**
 * 判断是否存在子文件夹
 * @param {*} folderPath
 * @returns boolean
 */
export function hasSubfolders(folderPath) {
  const subfolders = fs
    .readdirSync(folderPath, { withFileTypes: true })
    .filter((item) => item.isDirectory())
    .map((item) => item.name);

  return subfolders.length > 0;
}
/**
 * 判断是否存在文件
 * @param {*} folderPath
 * @returns boolean
 */
export function hasSubfiles(folderPath) {
  const subfolders = fs.readdirSync(folderPath, { withFileTypes: true });

  return subfolders.length > 0;
}

/**
 * 删除文件
 * @param {*} filePath
 */
export function deleteFile(filePath) {
  fs.unlink(filePath, (err) => {
    if (err) {
      console.error(`Error deleting file: ${err}`);
    } else {
      console.log(`Deleted: ${filePath}`);
    }
  });
}
/**
 * 递归读取文件夹或文件状态
 * @param {*} nodeFunction
 * returns Promise
 */
const promisify = function (nodeFunction) {
  return function (...args) {
    return new Promise((resolve, reject) => {
      nodeFunction.call(this, ...args, (err, data) => {
        if (err) {
          reject(err);
        } else {
          resolve(data);
        }
      });
    });
  };
};

// promise化异步读取方法
export const readDir = promisify(fs.readdir);
export const fileStat = promisify(fs.stat);

/**
 * @desc 获取IPV4地址
 * @param req htttp.request
 * @return string 32位IP地址
 */
export function get_client_ipv4(req) {
  // 获取任意浏览器的IP地址，
  let ip =
    req.headers['x-forwarded-for'] ||
    req.ip ||
    req.connection.remoteAddress ||
    req.socket.remoteAddress ||
    req.connection.socket.remoteAddress ||
    '';
  // 获取到的IP地址中存在IPV4和IPV6的地址，我们只需要IPV4的地址
  if (ip.split(',').length > 0) {
    ip = ip.split(',')[0].match(/((?:\d+\.){3}\d+)/)[0];
  }
  return ip;
}
/**
 * 获取本地IP地址
 * @param {*} ver 4或6
 * @returns IP地址
 */
export function getLocalIPv(ver = 4) {
  const os = require('node:os');
  const osType = os.type(); // 系统类型
  const netInfo = os.networkInterfaces();
  let ip = '';
  if (osType === 'Windows_NT') {
    for (const dev in netInfo) {
      // win7的网络信息中显示为本地连接，win10显示为以太网
      if (dev === '本地连接' || dev === '以太网') {
        for (let j = 0; j < netInfo[dev].length; j++) {
          if (netInfo[dev][j].family === `IPv${ver}`) {
            ip = netInfo[dev][j].address;
            break;
          }
        }
      }
    }
  } else if (osType === 'Linux') {
    ip = netInfo.eth0[0].address;
  }
  return ip;
  // const interfaces = os.networkInterfaces();
  // for (const netDev in interfaces) {
  //   for (const netProt of interfaces[netDev]) {
  //     if (
  //       netProt.family === `IPv${ver}` &&
  //       !netProt.internal &&
  //       netProt.address !== '127.0.0.1'
  //     ) {
  //       return netProt.address;
  //     }
  //   }
  // }
}
/**
 * @desc 根据后缀名读取文件
 * @param pathname string 文件路径 url.parse(request.url).pathname
 * @param fs fs
 * @param request htttp.request
 * @param response https.response
 */
export function readFileBySuffixName(pathname, fs, request, response) {
  const ext = pathname.match(/((?:\.[^.]+)?)$/)[0]; // 取得后缀名
  const path = request.query.path;
  switch (
    ext // 根据后缀名读取相应的文件，设置响应头，并发送到客户端
  ) {
    case '.css':
    case '.js': {
      // 读取文件
      fs.readFile(`${decodeURI(path)}`, 'utf8', (err, data) => {
        if (err) throw err;
        response.writeHead(200, {
          // 根据不同的后缀设置不同的响应头
          'Content-Type': {
            '.css': 'text/css',
            '.js': 'application/javascript',
          }[ext],
        });
        response.write(data); // 发送文件数据到客户端
        response.end(); // 发送完成
      });
      break;
    }
    case '.gif':
    case '.jpg':
    case '.png': {
      // jpg、gif、png后缀的图片
      // 二进制读取文件
      fs.readFile(`${decodeURI(path)}`, 'binary', (err, data) => {
        if (err) throw err;
        response.writeHead(200, {
          'Content-Type': {
            '.gif': 'image/gif',
            '.jpg': 'image/jpeg',
            '.png': 'image/png',
          }[ext],
        });
        response.write(data, 'binary'); // 发送二进制数据
        response.end();
      });
      break;
    }
    case '.avi':
    case '.mkv':
    case '.mp4': {
      // 读取文件的状态
      fs.stat(`${decodeURI(path)}`, (err, stats) => {
        if (err) {
          if (err.code === 'ENOENT') {
            return response.sendStatus(404);
          }
          response.end(err);
        }
        // 断点续传，获取分段的位置
        const range = request.headers.range;
        if (!range) {
          // 206状态码表示客户端通过发送范围请求头Range抓取到了资源的部分数据
          // 416状态码表示所请求的范围无法满足
          return response.sendStatus(416);
        }
        // 替换、切分，请求范围格式为：Content-Range: bytes 0-2000/4932
        const positions = range.replace(/bytes=/, '').split('-');
        // 获取客户端请求文件的开始位置
        const start = Number.parseInt(positions[0]);
        // 获得文件大小
        const total = stats.size;
        // 获取客户端请求文件的结束位置
        const end = positions[1]
          ? Number.parseInt(positions[1], 10)
          : total - 1;
        // 获取需要读取的文件大小
        const chunksize = end - start + 1;

        response.writeHead(206, {
          'Accept-Ranges': 'bytes',
          'Content-Length': chunksize,
          'Content-Range': `bytes ${start}-${end}/${total}`,
          'Content-Type': 'video/mp4',
        });
        // 创建读取流
        const stream = fs
          .createReadStream(`${decodeURI(path)}`, {
            end,
            start,
          })
          .on('open', () => {
            stream.pipe(response); // 读取流向写入流传递数据
          })
          .on('error', (err) => {
            response.end(err);
          });
      });
      break;
    }
    case '.rar': {
      // 同步读取文件状态
      const stats = fs.statSync(`${decodeURI(path)}`);
      response.writeHead(200, {
        // 模板字符串
        'Content-Disposition': `attachment; filename = ${pathname.replace('/', '')}`,
        'Content-Length': stats.size,
        'Content-Type': 'application/octet-stream', // 相应该文件应该下载
      });
      // 管道流
      fs.createReadStream(`${decodeURI(path)}`).pipe(response);
      break;
    } // 以上都不匹配则使用默认的方法
    default: {
      fs.readFile(`${decodeURI(path)}`, 'utf8', (_err, data) => {
        if (_err) {
          response.setHeader('Content-Type', 'text/plain', 'charset=utf-8');
          response.end('找不到首页文件！');
        } else {
          response.writeHead(200, {
            'Content-Type': 'text/html;charset=utf-8',
          });
          response.write(data);
          response.end();
        }
      });
    }
  }
}
